package com.wei.czz.framework.common.handler;

import com.wei.czz.common.constant.Constant;
import com.wei.czz.common.exception.CzzException;
import com.wei.czz.framework.common.service.AsyncService;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wyw
 * date: 2023-05-03 21:42:18
 * className: ThrottleHandler 节流执行异步任务处理类
 * version: 2.0
 * description:
 */
@Component
@AllArgsConstructor
public class ThrottleHandler {

    private static final Logger log = LoggerFactory.getLogger(ThrottleHandler.class);

    private final AsyncService asyncService;

    private final ConcurrentHashMap<String, Long> map = new ConcurrentHashMap<>();

    /**
     * 运行节流方法
     * 根据参数键进行节流操作
     * @param runnable 目标方法
     * @param key      键
     * @param delay    延时时长
     * @param unit     单位
     */
    public void throttleRun(Runnable runnable, String key, long delay, TimeUnit unit) {
        long now = System.currentTimeMillis();
        // 设置值
        Long last = map.put(key, now);
        boolean isRun = Objects.isNull(last) || now - last > unit.toMillis(delay);
        log.info("执行节流任务。key={} now={} last={} isRun={}", key, now, last, isRun);
        if (isRun) {
            asyncService.execute(runnable);
            asyncService.schedule(() -> {
                // 删除key
                map.remove(key);
            }, delay, unit);
        }
    }

    /**
     * 运行节流方法
     * 根据参数键进行节流操作
     * @param runnable  目标方法
     * @param key       键
     * @param passCount 放行数
     * @param delay     延时时长
     * @param unit      单位
     */
    public void throttleRun(Runnable runnable, String key, int passCount, long delay, TimeUnit unit) {
        if (passCount <= 0) {
            log.error("运行防抖方法，放行数量不能小于等于零");
            throw new CzzException();
        }
        // 重新生成key
        int count = ThreadLocalRandom.current().nextInt(passCount);
        key = key + Constant.SPLIT + count;
        // 执行
        this.throttleRun(runnable, key, delay, unit);
    }

    /**
     * 获取所有key
     * @return key集合
     */
    public Set<String> keys() {
        return Collections.unmodifiableSet(map.keySet());
    }

    /**
     * 删除节流key操作
     * @param key 键
     * @return 删除结果[true-键存在且删除 false-键不存在]
     */
    public boolean removeKey(String key) {
        return Objects.nonNull(map.remove(key));
    }

    /**
     * 清空所有key操作
     */
    public void clearKey() {
        map.clear();
    }
}
